{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#NumPy, Matplotlib, and other packages are throughout these notebooks\n",
    "# to fulfill Julia built-in features (array casting, sparse vectors) \n",
    "#and VMLS companion package imports (e.g. Plot)\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.1 Vectors\n",
    "Vectors are represented as one-dimensional Array objects, and assigned with '='"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([-1.1,  0. ,  3.6, -7.2]), array([-1.1,  0. ,  3.6, -7.2]), 4, 4)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([-1.1,0.0,3.6,-7.2])\n",
    "y = np.array([-1.1,0.0,3.6,-7.2])\n",
    "x,y, len(x), len(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1, 2]), (1, 2))"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,2])\n",
    "b = (1,2)\n",
    "a,b #a is a vector, b is a tuple of scalars "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Indexing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-7.2, 3.6)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[3], x[2] #Julia is 1-indexed, Python is 0-indexed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.1,  0. ,  4. , -7.2])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[2] = 4.0\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Assignment versus Copying"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.1,  0. ,  4. ,  4. ])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = x\n",
    "x[3] = 4.0\n",
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.1,  2. ,  4. ,  4. ])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y[1] = 2.0\n",
    "x #Same as in Julia, and different from MatLab/Octave: \n",
    "  #assigning an array to another doesn't make a new copy of the values\n",
    "  #it just createss a new reference to the same values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([-1.1,  0. ,  4. , -7.2]), array([ 2. ,  0. ,  3.6, -7.2]))"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([-1.1,0.0,3.6,-7.2])\n",
    "y = x.copy() #equivalent to copy(x) in Julia, \n",
    "             #resolves the new reference topic from above\n",
    "x[2] = 4.0\n",
    "y[0] = 2.0\n",
    "x,y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ True, False, False,  True]), array([ True,  True,  True,  True]))"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([-1.1,0.0,3.6,-7.2])\n",
    "y = x.copy()\n",
    "y[2] = 4.0\n",
    "# y==x #relational operators in Julia check the entire vector to determine a single boolean expression\n",
    "       #relational operators in Python check each individual vector value\n",
    "z=x.copy()\n",
    "z[1] = 4.0\n",
    "x[1] = 4.0\n",
    "y == x, z == x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1.3]), 1.3, array([ True]), True, False)"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([1.3])\n",
    "y = 1.3\n",
    "x,y, x==y, x[0]==y, type(x)==type(y)\n",
    "#Different from Julia: the third result would be false \n",
    "#because they're different types (array and int), just like the 5th result\n",
    "#the fourth result is the same, barring 0,1 indexing differences"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Block or Stacked Vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1, -2,  1,  1,  0])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#In Julia you concatenate vectors using semicolon or vcat: [x;y] or vcat(x,y)\n",
    "#In Python you can use:\n",
    "x = np.array([1,-2]); y = np.array([1,1,0]);\n",
    "z = np.concatenate((x,y))\n",
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Subvectors and Slicing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([4, 3, 0])"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([9,4,3,0,5])\n",
    "y = x[1:4] #slicing in python is [inclusive:exclusive], in julia: [inclusive:inclusive]\n",
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 9,  4,  3, -2, -3])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[3:5] = [-2,-3] #would be x[4:5] in Julia\n",
    "                 #as though Julia says: items i through j; Python says: from item i to item j\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ 9,  4,  3, -2, -3]), array([3, 4]))"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#In Julia a reverse slice is: [end:-1:1] ie [start:increment:end]\n",
    "#In Python a reverse slice is: [::-1] ie [start:end:increment]\n",
    "x,x[2:0:-1] #would be: x[3:-1:2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Vector of First Differences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1,  0, -2,  4])"
      ]
     },
     "execution_count": 123,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Julia successively compiles an array when running:\n",
    "#x = [1,0,0,-2,2]\n",
    "#d = x[2:end] - x[1:end-1]; which gives the vector of differences \n",
    "#But in python you have to run a list comprehension:\n",
    "x = np.array([1,0,0,-2,2])\n",
    "np.array([x[i+1]-x[i] for i in range(len(x)-1)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 1.,  0.],\n",
       "        [ 1., -1.],\n",
       "        [ 0.,  1.]]),\n",
       " (array([1., 0.]), [1.0, -1.0], [0, 1.0]),\n",
       " array([ 1., -1.]))"
      ]
     },
     "execution_count": 135,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([1.0,0]);y = ([1.0,-1.0]);z = ([0,1.0])  #tuple and list differences are the same\n",
    "lst0 = np.array([x,y,z])\n",
    "lst1 = (x,y,z)\n",
    "lst0,lst1,lst0[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Zero Vectors, Unit Vectors, Ones Vector, Random Vector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 0., 0.])"
      ]
     },
     "execution_count": 137,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.zeros(3) #In Julia you can use \"zeros(3)\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 1., 0.])"
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "i = 1; n =3\n",
    "ei = np.zeros(n)\n",
    "ei[i] = 1\n",
    "ei"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 1., 0., 0.])"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#inline function to make ei^ in Julia: \n",
    "#Unit_vector(i,n) = [zeros(i-1);1;zeros(n-i)]\n",
    "#inline function to make ei^ in Python:\n",
    "def unit_vector(i,n): return np.concatenate((np.zeros(i),[1],np.zeros(n-i)))\n",
    "unit_vector(i,n)\n",
    "#concatenation is slightly different in that you use np.concatenate and numpy requires explicitly same types to concatenate whereas Julia assumes this "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 1.])"
      ]
     },
     "execution_count": 159,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.ones(2) #equiv to ones(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.62559265,  0.70011423])"
      ]
     },
     "execution_count": 161,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.random.randn(2) #equiv to rand(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[64,\n",
       " 76,\n",
       " 69,\n",
       " 76,\n",
       " 60,\n",
       " 69,\n",
       " 78,\n",
       " 78,\n",
       " 73,\n",
       " 62,\n",
       " 66,\n",
       " 73,\n",
       " 78,\n",
       " 68,\n",
       " 68,\n",
       " 64,\n",
       " 77,\n",
       " 70,\n",
       " 61,\n",
       " 71,\n",
       " 63,\n",
       " 66,\n",
       " 65,\n",
       " 66,\n",
       " 78,\n",
       " 72,\n",
       " 63,\n",
       " 72,\n",
       " 72,\n",
       " 78,\n",
       " 60,\n",
       " 63,\n",
       " 66,\n",
       " 61,\n",
       " 66,\n",
       " 60,\n",
       " 71,\n",
       " 69,\n",
       " 72,\n",
       " 70]"
      ]
     },
     "execution_count": 181,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "temps = [np.random.randint(60,80) for i in range(40)]\n",
    "temps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 208,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "#in Julia you enter: ']', add [package name], ctrl+c (exit), use [package name]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 209,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(temps)\n",
    "plt.savefig('temps.png')\n",
    "#in Julia you use plot(temps) and savefig(\"temperature.pdf\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.2, 1.3 Vector Addition, Scalar-Vector Multiplication & Addition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 215,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1, 9, 3]), [0, 7, 3, 1, 2, 0])"
      ]
     },
     "execution_count": 215,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array([0,7,3])+np.array([1,2,0]), [0,7,3] + [1,2,0]\n",
    "#In Julia you can use the right result to get the left result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 216,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 8])"
      ]
     },
     "execution_count": 216,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array([1,9]) - np.array([1,1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 218,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0. ,  4.4, -2.2])"
      ]
     },
     "execution_count": 218,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([0,2,-1]) \n",
    "2.2*x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 219,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.        ,  0.66666667, -0.33333333])"
      ]
     },
     "execution_count": 219,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x/3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 225,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/vb/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in true_divide\n",
      "  \"\"\"Entry point for launching an IPython kernel.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([ inf,  1.5, -3. ])"
      ]
     },
     "execution_count": 225,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3 / x #In Julia this returns the same as x/3!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 227,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.3, -5.1, -1.1])"
      ]
     },
     "execution_count": 227,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array([1.1,-3.7,.3]) - 1.4 #In Julia this is .-; just using - returns an Error no method matching -"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 228,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.7, -0.3])"
      ]
     },
     "execution_count": 228,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    ".7 + np.array([1,-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Elementwise Operations, Elementwise Operations with a Scalar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 229,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.04063205, -0.0223914 ,  0.00634138])"
      ]
     },
     "execution_count": 229,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p_init = np.array([22.15,89.32, 56.77])\n",
    "p_fin = np.array([23.05,87.32, 57.13])\n",
    "r = (p_fin - p_init) / p_init #in Julia you would use ./ to denote elementwise \n",
    "r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(False, array([ True,  True, False]), False)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w = [1,2,2]; z = [1,2,3]\n",
    "w == z,np.array(w) == np.array(z), np.array_equal(w,z) \n",
    "#in Julia you can differentiate the two methods of relational \n",
    "#checking with == and .== "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 236,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1.1, -1.5]"
      ]
     },
     "execution_count": 236,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([1.1,.5,-1.5,-.3])\n",
    "[i for i in x if abs(i)>1] #in Julia: x[abs.(x) .> 1], you ask x for a slice using an elementwise absolute check (abs.(x)) and element wise comparator (.>)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 260,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.75287517,  0.10381592,  0.61324229,  1.61375533])"
      ]
     },
     "execution_count": 260,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.random.randn(4) #in Julia: x = rand(4)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.        ,  1.        ,  0.61324229,  1.61375533])"
      ]
     },
     "execution_count": 264,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[0:2] = [-1,1]\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 265,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1.        ,  1.3       ,  1.3       ,  1.61375533])"
      ]
     },
     "execution_count": 265,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[1:3] = 1.3\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Linear Combination"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 273,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1, 2]), array([3, 4]), -0.5, 1.5)"
      ]
     },
     "execution_count": 273,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a,b = np.array([1,2]), np.array([3,4])\n",
    "alpha,beta = -.5,1.5\n",
    "a,b,alpha,beta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 275,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([4., 5.])"
      ]
     },
     "execution_count": 275,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = alpha*a + beta*b\n",
    "c #all same as Julia, just take out np array casting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 342,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([4., 5.]), [array([4., 5.])])"
      ]
     },
     "execution_count": 342,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "coef = ([-.5,1.5])\n",
    "vecs = [np.array([1,2]),np.array([3,4])]\n",
    "\n",
    "def lincomb(coeff,vectors):\n",
    "    n = len(vectors[0])\n",
    "    a = np.zeros(n)\n",
    "    for i in range(len(vectors)):\n",
    "        a += coeff[i] * vectors[i]\n",
    "    return a\n",
    "\n",
    "#or, you can use a List Comprehension:\n",
    "\n",
    "def lincomb_LC(coeff,vectors):\n",
    "    return [coef[i] * vecs[i] + coef[i+1] * vecs[i+1] \n",
    "            for i in range(len(coef)-1)]\n",
    "    #or: sum([coef[i] * vecs[i] for i in range(len(vecs))])\n",
    "\n",
    "lincomb(coef, vecs), lincomb_LC(coef,vecs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 358,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.58071614, 0.95006838, 0.70374892]),\n",
       " array([0.0838133 , 0.93309517, 0.70677085]),\n",
       " 0.06290415585640763)"
      ]
     },
     "execution_count": 358,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a,b,beta = np.random.rand(3),np.random.rand(3), np.random.rand()\n",
    "a,b,beta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Checking properties"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 359,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.04180166, 0.11845881, 0.08872756]),\n",
       " array([0.04180166, 0.11845881, 0.08872756]))"
      ]
     },
     "execution_count": 359,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lhs = beta*(a+b)\n",
    "rhs = beta*a + beta * b\n",
    "lhs,rhs #same as Julia for checking distributive property"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.4 Inner Product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 361,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-7"
      ]
     },
     "execution_count": 361,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([-1,2,2])\n",
    "y = np.array([1,0,-3])\n",
    "np.inner(x,y) #Julia equiv: x'*y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### NPV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 366,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([1.        , 0.95238095, 0.90702948, 0.8638376 ]), 1.236162401468524)"
      ]
     },
     "execution_count": 366,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = np.array([.1,.1,.1,1.1])\n",
    "n = len(c)\n",
    "r = .05\n",
    "d = np.array([(1+r)**-(i) for i in range(0,n)]) #J equiv: (1+r) .^ -(0:n-1)\n",
    "d, sum(c*d) #NPV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Total School-Age Population"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 425,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "150.0"
      ]
     },
     "execution_count": 425,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Ambiguous solution to attempt at \"Total school-age population\", \n",
    "#unable to decipher description of data given\n",
    "import collections\n",
    "from collections import Counter\n",
    "\n",
    "s = np.concatenate((np.zeros(5),np.ones(14),np.zeros(81)))\n",
    "ages = [np.random.randint(5,19) for i in range(100)]\n",
    "# data = dict(collections.OrderedDict(sorted(data.items())))\n",
    "# counts = np.array([v for k,v in data.items()])\n",
    "# dists = np.array([v/100 for k,v in data.items()])\n",
    "sum(s*ages) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.5 Complexity of Vector Computations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 428,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.4455070365899001, 0.44550703658990015)"
      ]
     },
     "execution_count": 428,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a,b = np.random.randn(),np.random.randn()\n",
    "lhs = (a+b)*(a-b)\n",
    "rhs = a**2 - b**2\n",
    "lhs,rhs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 436,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8.75 ms ± 550 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "import timeit\n",
    "a,b = np.random.randn(10**5),np.random.randn(10**5)\n",
    "%timeit sum(a*b) #@time in J"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 435,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8.79 ms ± 495 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit sum(a*b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 448,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((array([123456, 123457]),), 1)"
      ]
     },
     "execution_count": 448,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sparsevec = np.zeros(10**6)\n",
    "sparsevec[123456],sparsevec[123457] = [1.0,-1.0] \n",
    "#this is a one line operation in J using the SparseVec package: \n",
    "#sparsevec([list of indices to set], [values for those indices], vec size)\n",
    "np.nonzero(sparsevec),len(np.nonzero(sparsevec))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 454,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.32 ms ± 84.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "b = np.random.randn(10**6)\n",
    "%timeit c = sparsevec + b "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
